﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using HasuSLLib;
using System.ComponentModel.DataAnnotations;

namespace HasuSLUI
{
    public partial class DataPanel : UserControl
    {
        #region Constructor and Page load event
        
        public DataPanel()
        {
            InitializeComponent();
            Loaded += new RoutedEventHandler(DataPanel_Loaded);
        }

        void DataPanel_Loaded(object sender, RoutedEventArgs e)
        {
            if (DynamicSize && this.Parent != null && (this.Parent is FrameworkElement))
            {
                (this.Parent as FrameworkElement).SizeChanged += new SizeChangedEventHandler(DataPanel_SizeChanged);
            }
        }

        void DataPanel_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            this.Width = (this.Parent as FrameworkElement).Width;             
        }

        #endregion

        #region UI Priperties

        private Column _columns = Column.Double;

        public Column Columns
        {
            get { return _columns; }
            set { _columns = value; }
        }

        private int _labelWidth = UIUtils.LabelWidth ;

        public int LabelWidth
        {
            get { return _labelWidth; }
            set { _labelWidth = value; }
        }

        private double _controlWidth = UIUtils.ControlWidth ;

        public double ControlWidth
        {
            get
            {
                if (_columns == Column.Double)
                    return (_controlWidth == 250 ? FullWidth / 2 : _controlWidth);
                else
                    return (_controlWidth == 250 ? FullWidth : _controlWidth);
            }
            set { _controlWidth = value; }
        }

        public double FullWidth
        {
            get { return this.Width - 44/*margin and scrollview scrolbaar*/  ; }
        }

        #endregion

        #region proprities

        #region DynamicSize

        private bool _dynamicSize = false;
        /// <summary>
        /// Dynamic Size (height and width)
        /// </summary>
        public bool DynamicSize
        {
            get { return _dynamicSize; }
            set { _dynamicSize = value; }
        }

        #endregion FullWidth 



        #region EnableClientValidation

        private bool _enableClientValidation = true;
        /// <summary>
        /// EnableClientValidation
        /// </summary>
        public bool EnableClientValidation
        {
            get { return _enableClientValidation; }
            set { _enableClientValidation = value; }
        }

        #endregion EnableClientValidation 

        
        #region NotifyOnValidationError

        private bool _notifyOnValidationError = true;

        /// <summary>
        /// EnableInvalidValueValidation
        /// </summary>
        public bool NotifyOnValidationError
        {
            get { return _notifyOnValidationError; }
            set { _notifyOnValidationError = value; }
        }

        #endregion EnableInvalidValueValidation 



        private Collection<GroupPanel> generatedGroupPanels = new Collection<GroupPanel>();

        public new object DataContext
        {
            get
            {
                return base.DataContext;
            }
            set
            {
                if (value == null)
                { throw new ArgumentNullException("DataContext" ,"DataContext can not be null"); } //NullReferenceException
                if (value is System.Collections.IEnumerable)
                { throw new ArgumentException("DataContext value can not be IEnumerable.", "DataContext"); } //InvalidCastException
                base.DataContext = value;
                resetControls();
                genratecontrols();
            }
        }


        List<Metadata> metadataList = null;

        public List<Metadata> MetadataList
        {
            get
            {
                return metadataList;
            }
        }

        #endregion

        #region private methods

        #region resetControls

        private void resetControls()
        {
            cmbGroups.Items.Clear();

            stkpnlMain.Children.Clear();

            generatedGroupPanels.Clear();
        }

        #endregion

        #region genratecontrols

        private void genratecontrols()
        {
            if (DataContext == null)
                return;
            
            this.lblTitle.Text = DataContext.ToString();

            metadataList = new List<Metadata>();

            metadataList = MetadataProvider.GetVisibleMetadataCollection(DataContext);

            //var sortedMetadataList = metadataList.OrderBy(x => x.Group).ThenBy(x => x.Order);

            var metaGroups = metadataList.
                GroupBy(x => new { GroupName = x.Group})
                .Select(grp => new { GroupName = grp.Key.GroupName, Count = grp.Count(), metadatas= grp.AsEnumerable() })
                .OrderBy( x=>x.GroupName).ThenBy(x =>x.metadatas.OrderBy(m=> m.Order))  ;

            foreach (var item in metaGroups)
            {
                GroupPanel groupPanel = null;
                if (this.HasGroupPanelsDefined)
                {
                    groupPanel = GetGroupPanel(item.GroupName);
                    if (groupPanel == null)
                    {
                        if (this.CrateGroupPanelIfNotDefined)
                        {
                           groupPanel = createGroupPanel(item.GroupName);
                        }
                        else
                        { continue; }
                    }
                }
                else
                {
                    groupPanel = createGroupPanel(item.GroupName);
                }

                generatedGroupPanels.Add(groupPanel);

                stkpnlMain.Children.Add(groupPanel);

                cmbGroups.Items.Add(item.GroupName);

                var metadatas = item.metadatas.OrderBy(o => o.Order);

                foreach (var metadata in metadatas)
                {
                    if (this.EnableClientValidation)
                    {
                        metadata.GetValidationRules();
                    }

                    metadata.NotifyOnValidationError = this.NotifyOnValidationError;

                    groupPanel.Children.Add(createMetaControl(metadata));
                }
            }
            metadataList.Clear();
        }

        #endregion

        #region createGroupPanel and GetGroupPanel

        private GroupPanel createGroupPanel(string groupName)
        {
            GroupPanel groupPanel = UIDefaults.CreateGroupPanel();
            groupPanel.Title = groupName;
            groupPanel.Width = FullWidth;
            return groupPanel;

        }

        #region GetGroupPanel

        protected GroupPanel GetGroupPanel(string groupPanelName)
        {
            var groupPanels = from groupPanel in GroupPanels
                              where groupPanel.Name == groupPanelName || groupPanel.Title == groupPanelName
                              select groupPanel;

            return groupPanels.Count() > 0 ? groupPanels.FirstOrDefault() : null;
        }


        protected MetaControl GetGroupPanel(GroupPanel groupPanel, string controlName)
        {
            var metaControls = from metaControl in groupPanel.Templates
                               where metaControl.Name == controlName
                               select metaControl;
            return metaControls.Count() > 0 ? metaControls.FirstOrDefault() : null; ;
        }

        #endregion

        #endregion

        #region createMetaControl

        private MetaControl createMetaControl(Metadata metadata)
        {
            MetaControl metaControl = UIDefaults.CreateMetaControl();
            
            metaControl = createMetaControl(metadata, metaControl);

            return metaControl;
        }

        private MetaControl createMetaControl(Metadata metadata ,MetaControl metaControl)
        {
            TextBlock tmpLabel = UIDefaults.DefaultControlFactory.CreateLabel(metadata, LabelWidth);

            Control tmptCnt = SupplyAdditionalControl(metadata);

            if (tmptCnt == null && SupplyAdditionalControlDelegate != null)
                tmptCnt = SupplyAdditionalControlDelegate(metadata);

            if (tmptCnt == null)
                tmptCnt = UIDefaults.DefaultControlFactory.CreateControl(metadata);

            if (tmptCnt != null)
            {
                UIDefaults.DefaultControlFactory.SetBinding(tmptCnt, metadata, this.DataContext);
                tmptCnt.Tag = metadata;

                SetSize(tmptCnt, metadata);
                if (metaControl == null)
                {
                    metaControl = UIDefaults.CreateMetaControl();
                    metaControl.Width = ControlWidth ;
                }
                
                metaControl.AddControls(tmpLabel, tmptCnt);
            }
            else
            {
                TextBlock unktblock = new TextBlock()
                { 
                    Text = "Unknown Control",
                    Width = (ControlWidth - LabelWidth)
                };

                if (metaControl == null)
                {
                    metaControl = UIDefaults.CreateMetaControl();
                    metaControl.Width = ControlWidth;
                }
                
                metaControl.AddControls(tmpLabel, unktblock); 
            }
            if (metadata.LableAt == HasuSLUI.LabelLocation.Left)
            {
                metaControl.Orientation = Orientation.Horizontal;
                metaControl.VerticalAlignment = VerticalAlignment.Top;
            }
            else
            {
                metaControl.Orientation = Orientation.Vertical;
                metaControl.HorizontalAlignment = HorizontalAlignment.Left;
            }

            metaControl.Tag = metadata;
            return metaControl;
        }

        #endregion

        #region Setsize

        private void SetSize(Control control, Metadata metadata)
        {
            if (control != null)
                control.Margin = UIDefaults.GetMargin();

            if (metadata.Visualization != null && control != null)
            {
                if (!metadata.Visualization.AutoSize)
                {
                    if (metadata.Visualization.FullWidth)
                        control.Width = FullWidth - LabelWidth;
                    else if (metadata.Visualization.Width > 0)
                        control.Width = ControlWidth - metadata.Visualization.Width;

                    if (metadata.Visualization.Height > 0)
                    {
                        control.Height = metadata.Visualization.Height;
                        //if textbox and string then set multy line
                        if (control is TextBox && metadata.MetaType == typeof(string))
                            (control as TextBox).TextWrapping = TextWrapping.Wrap;
                    }
                }
            }

        }

        #endregion

        #endregion

        #region HasMetaControlTemplatesDefined
        /// <summary>
        /// HasMetaControlTemplatesDefined
        /// </summary>
        protected bool HasMetaControlTemplatesDefined(GroupPanel  groupPanel)
        {
            return groupPanel.Templates.Count > 0;
        }

        #endregion HasMetaControlTemplatesDefined 

        #region HasGroupPanelsDefine
        /// <summary>
        /// GroupPanelsHasDefine
        /// </summary>
        protected bool HasGroupPanelsDefined
        {
            get { return GroupPanels.Count>0; }
        }

        #endregion GroupPanelsHasDefine 
        
        #region CrateMetaControlIfNotDefined
        private bool _crateMetaControlIfNotDefined  = true;
        /// <summary>
        /// CrateMetaControlIfNotDefined
        /// </summary>
        protected bool CrateMetaControlIfNotDefined
        {
            get { return _crateMetaControlIfNotDefined; }
            set { _crateMetaControlIfNotDefined = value; }
        }

        #endregion CrateMetaControlIfNotDefined 
        
        #region CrateGroupPanelIfNotDefined
        private bool _crateGroupPanelIfNotDefined = true;
        /// <summary>
        /// Crate GroupPanel If Not Defined
        /// </summary>
        protected bool CrateGroupPanelIfNotDefined
        {
            get { return _crateGroupPanelIfNotDefined; }
            set { _crateGroupPanelIfNotDefined = value; }
        }

        #endregion CrateGroupPanelIfNotDefined 

        #region Valid

        public bool Valid()
        {
            return Valid(new ErrorCollection());
        }

        public bool Valid(ErrorCollection errors)
        {
            Collection<ValidationResult> validationResults = new Collection<ValidationResult>();
            
            bool retVal= Validator.TryValidateObject(this.DataContext, new ValidationContext(this.DataContext, null, null), validationResults);
            
            return retVal;
        }

        #endregion

        #region DependencyProperty

        public static readonly DependencyProperty ControlsProperty
          = DependencyProperty.Register(
            "GroupPanels",
            typeof(Collection<GroupPanel>),
            typeof(DataPanel),
            new PropertyMetadata(new Collection<GroupPanel>())
        );

        public Collection<GroupPanel> GroupPanels
        {
            get
            {
                return (Collection<GroupPanel>)GetValue(ControlsProperty);
            }
        }

        /*
         * 
         * <local:DataPanel> 
         *   <local:DataPanel.GroupPanels> 
         *       <Button Content="A"/> 
         *       <Button Content="B"/> 
         *   </local:DataPanel.GroupPanels> 
         *</local:DataPanel> 
         */

        #endregion

        #region virtual methods

        public delegate void OverrideDefaultControldlgt(Metadata metadata, bool showLabel);

        public OverrideDefaultControldlgt OverrideDefaultControlDelegate = null;

        public virtual Control OverrideDefaultControl(Metadata metadata, bool showLabel)
        {
            return null;
        }

        public delegate Control dlgSupplyAdditionalControl(Metadata metadata);

        public dlgSupplyAdditionalControl SupplyAdditionalControlDelegate = null;

        public virtual Control SupplyAdditionalControl(Metadata metadata)
        {
            return null;
        }

        #endregion

        #region code not in use
        /*
         private void CreateControl(Metadata metadata)
        {
            bool bNextPanelCreateNew = false;
            if (metadata.Visualization != null && metadata.Visualization.FullWidth)
                bNextPanelCreateNew = true;

            StackPanel tmpStkPnl = null;
            //
            if (prevousStkPnl == null || bNextPanelCreateNew || prevousGropu != metadata.GroupName)
            {
                if (prevousGropu != metadata.GroupName)
                {
                    stkpnlMain.Children.Add(CreateGroupPanel(metadata.GroupName));
                }

                tmpStkPnl = CreatePanel();

                //create new panel if curren control is full size 
                if (bNextPanelCreateNew)
                    prevousStkPnl = null;
                else
                    prevousStkPnl = tmpStkPnl;

                stkpnlMain.Children.Add(tmpStkPnl);
            }
            else
            {
                tmpStkPnl = prevousStkPnl;
                prevousStkPnl = null;
            }

            TextBlock tmpLabel = GetLabel(metadata.Title, LabelWidth);

            tmpStkPnl.Children.Add(tmpLabel);

            Control tmptCnt = SupplyAdditionalControl(metadata);

            if (tmptCnt == null && SupplyAdditionalControlDelegate != null)
                tmptCnt = SupplyAdditionalControlDelegate(metadata);

            if (tmptCnt == null)
                tmptCnt = UIDefaults.DefaultControlFactory.CreateControl(metadata);

            if (tmptCnt != null)
            {
                UIDefaults.DefaultControlFactory.SetBinding(tmptCnt, metadata, this.DataContext);
                tmptCnt.Width = ControlWidth - LabelWidth;
                tmptCnt.Tag = metadata;
                //UIGenerator.SetEventAndValue(tmptCnt, metadata);
                //UIGenerator.SetToolTip(tmptCnt, metadata);

                SetSize(tmptCnt, metadata);

                tmpStkPnl.Children.Add(tmptCnt);
            }
            else
            {
                TextBlock unktblock = GetLabel("Unknown Control", (ControlWidth - LabelWidth));

                tmpStkPnl.Children.Add(unktblock);
            }
        }

        private UIElement CreateGroupPanel(string groupName)
        {
            prevousGropu = groupName;

            cmbGroups.Items.Add(groupName);

            Border grpHeaderPnl = new Border()
            {
                Margin = UIDefaults.GetMargin(),
                CornerRadius = new CornerRadius(7),
                HorizontalAlignment = HorizontalAlignment.Left,
                Width = FullWidth,
                Background = new SolidColorBrush()
                {
                    Color = Colors.Blue
                },
                Child = new TextBlock()
                {
                    Text = prevousGropu,
                    Foreground = new SolidColorBrush() { Color = Colors.White }
                }
            };
            return grpHeaderPnl;
        }

        private StackPanel CreatePanel()
        {
            StackPanel tmpStkPnl = new StackPanel()
            {
                Margin = UIDefaults.GetMargin(),
                Orientation =  Orientation.Horizontal,
                HorizontalAlignment = HorizontalAlignment.Left,
                Width = FullWidth
            };
            return tmpStkPnl;
        }

        private void setDataBinding(Metadata metadata, Control control)
        {
            var binding = new System.Windows.Data.Binding(metadata.Name);
            binding.Source = this.DataContext;
            control.SetBinding(TextBox.TextProperty, binding);
        }
         */
        #endregion

    }

}
